package com.auditlog.boot.aop;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import com.auditlog.boot.annotations.AuditLog;
import com.auditlog.boot.config.AuditLogProperties;
import com.auditlog.datasource.context.ContextHolder;
import com.auditlog.datasource.context.ExecutionContext;
import com.auditlog.datasource.context.LogContext;
import com.auditlog.datasource.context.LogContextHolder;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * @author Zhiyang.Zhang
 * @version 1.0
 * @date 2022/12/4 21:41
 */
@Aspect
@AllArgsConstructor
@Order(0)
public class AuditLogAspect {

    private AuditLogProperties auditLogProperties;

    @Around("@annotation(auditLog)")
    @SneakyThrows
    public Object around(ProceedingJoinPoint joinPoint, AuditLog auditLog) throws Throwable {
        try {
            Signature signature = joinPoint.getSignature();
            if (!(signature instanceof MethodSignature)) {
                return joinPoint.proceed();
            }
            initConfig(auditLog);
            Object result = joinPoint.proceed();
            return result;
        } finally {
            LogContextHolder.clear();
            ContextHolder.clear();
        }
    }

    /**
     * 初始化配置信息
     */
    private void initConfig(AuditLog auditLog) {
        LogContext logContext = LogContextHolder.get();
        logContext.setAudit(true);
        logContext.setOnExceptionContinue(auditLog.onExceptionContinue());
        Set<String> ignoreTables = new HashSet<>();
        // 全局 + 注解
        if (ArrayUtil.isNotEmpty(auditLog.ignoreTables())) {
            ignoreTables.addAll(Arrays.asList(auditLog.ignoreTables()));
        }
        if(CollectionUtil.isNotEmpty(this.auditLogProperties.getIgnoreTables())){
            ignoreTables.addAll(this.auditLogProperties.getIgnoreTables());
        }
        logContext.setIgnoreTables(ignoreTables);
        // 优先使用注解上的配置
        boolean caseSensitive = auditLog.caseSensitive();
        if (!caseSensitive) {
            caseSensitive = this.auditLogProperties.isCaseSensitive();
        }
        logContext.setCaseSensitive(caseSensitive);
        ContextHolder.getConnectionContext().setOnExceptionContinue(auditLog.onExceptionContinue());
        ExecutionContext executeContext = ContextHolder.getExecuteContext();
        executeContext.setOperationName(auditLog.operationName());
        executeContext.setAudit(true);
    }

}
